#pragma once

#include <iostream>
#include <memory>
#include <poll.h>
#include "socket.hpp"

using namespace socket_net;
class PollServer
{
    const static int defaultfd = -1; // 默认fd为-1
    const static int gnum = 1024;
    const static int gevents = 0;

public:
    PollServer(uint16_t port) : _port(port), _ListenSock(make_unique<TcpSocket>()),_timeout(-1)
    {
        InetAddr addr("0", _port);
        _ListenSock->BuildListenSocket(addr);
        for (auto &it : _rfds)
        {
            it.fd = defaultfd;
            it.events = it.revents = gevents;
        }
        _rfds[0].fd=_ListenSock->sockfd();
        _rfds[0].events=POLLIN;//// 表示对读事件关心(listensock上有新连接，就是读事件就绪)
    }
    ~PollServer()
    {
    }
    void AcceptClient()
    {
        // 只关心读，而读有listensock和normalsock
        InetAddr clientaddr;
        int sockfd = _ListenSock->Acceptaddr(&clientaddr);
        if (sockfd < 0)
            return;
        Log(DEBUG, "Get new Link, sockfd: %d, client info %s:%d\n", sockfd, clientaddr.ip().c_str(), clientaddr.port());
        // read/recv(sockfd); send(sockfd)?? 不能. 必须将新的fd，托管给select。如何托管呢？？？
        // 只要将新的fd添加到辅助数组中即可。
        int pos = 0;
        for (; pos < gnum; pos++)
        {
            if (_rfds[pos].fd == defaultfd)
                break;
        }
        if (pos == gnum)
        {
            ::close(sockfd);
            Log(WARNING, "server is full...");
            return;
        }
        else
        {
            _rfds[pos].fd = sockfd;
            _rfds[pos].events=POLLIN;
            _rfds[pos].revents=gevents;
            Log(DEBUG, "%d add to select arry!", sockfd);
        }
        Log(DEBUG, "curr fd_array[] fd list : %s", RfdsToString().c_str());
    }

    void ServerIO(int pos)
    {
        char buffer[1024];
        ssize_t n = ::recv(_ListenSock->sockfd(), buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            cout << "client say:" << buffer << endl;
            string echostring = "[server echo#] ";
            echostring += buffer;
            ::send(_rfds[pos].fd, echostring.c_str(), echostring.size(), 0);
        }
        else if (n == 0)
        {
            Log(DEBUG, "%d is closed", _rfds[pos].fd);
            ::close(_rfds[pos].fd);
            _rfds[pos].fd = defaultfd;
            _rfds[pos].events=_rfds[pos].revents=gevents;
            Log(DEBUG, "curr fd_array[] fd list : %s", RfdsToString().c_str());
        }
        else
        {
            Log(DEBUG, "%d recv is error", _rfds[pos].fd);
            ::close(_rfds[pos].fd);
            _rfds[pos].fd = defaultfd;
            Log(DEBUG, "curr fd_array[] fd list : %s", RfdsToString().c_str());
        }
    }
    void HanderEvents()
    {
        for (int i = 0; i < gnum; i++)
        {
            if (_rfds[i].fd == defaultfd)
                continue;
            int fd=_rfds[i].fd;
            short revents=_rfds[i].revents;
            if(revents&POLLIN)
            {
                if(fd==_ListenSock->sockfd())
                {
                    AcceptClient();
                }
                else
                {
                    ServerIO(i);
                }
            }
            if(revents&POLLOUT)
            {
                //todo
            }
        }
    }
    std::string RfdsToString()
    {
        std::string fdstr;
        for (int i = 0; i < gnum; i++)
        {
            if (_rfds[i].fd == defaultfd)
                continue;
            fdstr += std::to_string(_rfds[i].fd);
            fdstr += " ";
        }
        return fdstr;
    }
    void loop()
    {
        while (true)
        {
            // listensocket 等待新连接到来，等价于对方给我发送数据！我们作为读事件同一处理
            // 新连接到来 等价于 读事件就绪！
            // 首先要将listensock添加到select中！
            int n=poll(_rfds,gnum,0);
            switch (n)
            {
            case 0:
                Log(DEBUG, "timeout.....%d:%d");
                break;
            case -1:
                Log(DEBUG, "select error...");
                break;
            default:
                Log(DEBUG, "Event things happen!n: %d", n);
                HanderEvents();
                break;
            }
        }
    }

private:
    uint16_t _port;
    unique_ptr<Socket> _ListenSock;
    struct pollfd _rfds[gnum];
    int _timeout;
};